package com.acxy.ants.core.handler;

import com.acxy.ants.common.enums.RequestMethod;
import com.acxy.ants.common.enums.ResponseCode;
import com.acxy.ants.common.enums.ViewType;
import com.acxy.ants.common.kit.StrKit;
import com.acxy.ants.core.BindingParams;
import com.acxy.ants.core.Handler;
import com.acxy.ants.core.LogReporter;
import com.acxy.ants.core.config.Constants;
import com.acxy.ants.core.proxy.CGLibProxy;
import com.acxy.ants.resful.Mapping;
import com.acxy.ants.resful.MappingMatch;
import com.acxy.ants.resful.RequestMapping;
import com.acxy.ants.resful.doc.ApiDocKit;
import com.acxy.ants.resful.render.Json;
import com.acxy.ants.resful.render.Resource;
import com.acxy.ants.resful.render.View;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 核心handler处理,也是最后一个handler
 * @author MrShun
 * @version 1.0
 * @Date 2017-04-27
 */
public class RenderHandler implements Handler {

    private final List<RequestMapping> requestMappings;

    private final Constants constants;

    public RenderHandler(Constants constants) {
        this.requestMappings = Mapping.getMappings();
        this.constants = constants;
    }


    public boolean preHandle(String target, HttpServletRequest request, HttpServletResponse response) throws Exception {
        RequestMapping result = MappingMatch.match(requestMappings, target);
        //匹配不到请求直接放回到过滤器
        if(result == null)
            return true;
        else {
            String type = request.getMethod();
            RequestMethod requstType = result.getRequstType();
            //判断请求类型 为null时都能访问
            if (requstType == null || type.equals(String.valueOf(requstType))) {

                //参数绑定并且进行数据校验
                Object[] args = BindingParams.bingingValidate(target, result, request, response);

                Object obj = result.getObject();
                Method method = result.getMethod();
                method.setAccessible(true); //取消方法类型检查提高性能
                Object data = method.invoke(CGLibProxy.createProxy(obj), args);

                LogReporter.action(target, request, result);
                Class<?> returnType = method.getReturnType();

                //TODO 如果为Debug模式并且参数含有doc参数, 则生成api文档
                String doc = request.getParameter("doc");
                if(constants.isDebug() && doc != null){
                    //文档生成操作
                    ApiDocKit.createDoc(target, result.getUrls(), request, method, data);
                }
                if (data != null) { //有返回值的时候
                    if (returnType == String.class) {
                        //重定向
                        if(String.valueOf(data).indexOf("redirect:") !=-1){
                            String rect = String.valueOf(data).split("redirect:")[1];
                            response.sendRedirect(request.getContextPath() + rect);
                            return true;
                        }
                        ViewType viewType = constants.getViewType();
                        String viewName = StrKit.setInitial(String.valueOf(data), "/");
                        response.setContentType("text/html");
                        if (viewType == ViewType.JSP || viewType == ViewType.HTML) {
                            RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewName);
                            requestDispatcher.forward(request, response);
                        }else
                            View.render(constants, viewName, request, response);
                    }else if(returnType == Resource.class){
                        Resource res = (Resource)data;
                        //TODO 读取jar里面资源文件输出
                        res.render(constants.getError404Page(), result.getModuleName(), request, response);
                    }else if(returnType == Object.class) {
                        Json.writeJson(data, response, true);
                    }else {
                        //返回Response响应数据, 不带序列化
                        Json.writeJson(data, response, false);
                    }
                }
            } else {
                Json.writeJson(Json.exception(ResponseCode.REQUEST_TYPE_ERROR), response);
            }
            return false;
        }
    }
}